/*==============================================================================
**                                  Cuong Chu
**                      Proprietary - Copyright (C) 2014
**------------------------------------------------------------------------------
** Supported MCUs      : MCU STM32
** Supported Compilers : KeilC
**------------------------------------------------------------------------------
** File name         : APP_M3_PORTB.c
**  
** Module name       : PORT B
**
** Summary:
**
**= History ===================================================================
** 00.00.01  28/7/2014  Cuong Chu
** - Creation
==============================================================================*/
/******************************************************************************/
/* INCLUSIONS                                                                 */
/******************************************************************************/
#include "comm/comm.h"
#include "bsp/input.h"
#include "tim/timer.h"
#include "fls/fls.h"
/*******************************************************************************/
/* DEFINITION OF CONSTS                                                        */
/*******************************************************************************/
#define PORT_NODE_ID                  0xAABBCC0B
#define HOST_NODE_ID                  0xAABBCCEE
#define COMMUNICATION_PORT            COMM_COM2
#define   NULL_VAL                    0x00
#define   DATA_ADDRESS                0x0800A800
/*******************************************************************************/
/* DECLARATION OF LOCAL TYPEDEFS                                               */
/*******************************************************************************/
/* flag start/stop checks cable */
typedef enum
{
  FLG_START_CHECK,
  FLG_STOP_CHECK
}APP_PORT_FlagType;

/* process checking  */
typedef enum
{
  CHK_STARTING,
  CHK_CHECKING,
  CHK_REPORT
}APP_PORT_CableCheckingStateType;
/* client control ID */
typedef enum
{
  SS_MODE_SWITCHING         = 0x11,
  SS_MODE_CABLE_DETECTED    = 0x12,
  SS_MODE_START_CHECK       = 0x13,
  SS_MODE_CHECKING          = 0x14,
  SS_MODE_CABLE_FAILED      = 0x15,
  SS_MODE_CABLE_PASSED      = 0x16,
  SS_MODE_START_DETECT      = 0x17,
  SS_MODE_SET_NBR_WIRES     = 0x18
}APP_PORT_CmdFromHostType;
/* action mode */
typedef enum
{
  MODE_AUTO   = 0x01,
  MODE_MANUAL = 0x02
}APP_MAIN_ActionModeType;
/* command  */
typedef struct
{
  APP_PORT_CmdFromHostType      Cmd;
  void                          (*func)(ComM_MessageType* msg);
}APP_PORT_CommandType;

/* main structure */
typedef struct
{
  uint16_t                FirstSetup;
  APP_MAIN_ActionModeType ActionMode;
  uint8_t                 NbrOfWireToCheck ;  
}APP_MAIN_TypeDef;


/*******************************************************************************/
/* DECLARATION OF LOCAL FUNCTIONS                                              */
/*******************************************************************************/
/*******************************************************************************
** Function name: APP_MAIN_SavingData( void  )
** Description  : The function store configuration data to flash memory
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_SavingData
(
  void
);
/*******************************************************************************
** Function name: APP_MAIN_StartupValueSetting( void  )
** Description  : The function starts up all parameters
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_StartupValueSetting
(
  void
);

/* process command from host  */
static void Port_iProcessHostCommand
(
  ComM_MessageType* msg
); 
/* process command switching mode  */
static void Port_iCmdSwitchingMode
(
  ComM_MessageType* msg
); 
/* process command from host  */
static void Port_iCmdStartCheck
(
  ComM_MessageType* msg
); 
/* process command from host  */
static void Port_iCmdChecking
(
  ComM_MessageType* msg
); 

/* process auto detect cable  */
static void Port_AutoDetecting
(
  void
); 
/* thread check auto or manual mode */
static void Port_iStartDetect
(
  ComM_MessageType* msg
);

/* thread set nbr of wires to check */
static void Port_iSetCableLenght
(
  ComM_MessageType* msg
);


/*******************************************************************************/
/* DECLARATION OF LOCAL VARIABLES                                              */
/*******************************************************************************/
static const APP_PORT_CommandType    HostCommand[5] = 
{
  {
    SS_MODE_SWITCHING,
    Port_iCmdSwitchingMode
  },
  {
    SS_MODE_START_CHECK,
    Port_iCmdStartCheck
  },
  {
    SS_MODE_CHECKING,
    Port_iCmdChecking
  },
  {
    SS_MODE_START_DETECT,
    Port_iStartDetect
  },
  {
    SS_MODE_SET_NBR_WIRES,
    Port_iSetCableLenght
  }
};
static APP_PORT_FlagType                         CheckingStatus = FLG_STOP_CHECK;

/* Rx Message */
static ComM_MessageType                          RxMsg;
/* Tx Message */
static ComM_MessageType                          TxMsg;
/* cable is detected flag  */
static uint8_t                                   CableDetected = 0;
/* time for cable is available again */
static uint32_t                                   BackTime = 0;

/* main data structure */
static APP_MAIN_TypeDef             CableVerify;
/* confirm cable length to check */
static uint8_t                      FlagCableLengthValid = 0;
/*******************************************************************************/
/* DECLARATION OF LOCAL VARIABLES                                              */
/*******************************************************************************/
static void Test_Input(void)
{
	INPUT_InputType  i;
	for(i = IN_CH_1; i <= IN_CH_64; i++)
  {
   INPUT_ReadInput(i);
  }
}
/*******************************************************************************
** Function name: main( void  )
** Description  : The main function
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
int main(void)
{
  INPUT_InputType  i;
  /* init comm */
  ComM_Init(PORT_NODE_ID,COMMUNICATION_PORT);
  /* enabled interrupt request */
  ComM_EnableReceivePort(COMMUNICATION_PORT);
  /* init timer */
  Timer_SystemTickTimerInit();
  /* input clocks supply */
  INPUT_IOEnableClock();
  /* init input */
  for(i = IN_CH_1; i <= IN_CH_64; i++)
  {
   INPUT_InputInit(i);
  }
	Test_Input();
  APP_MAIN_StartupValueSetting();
  // /* check cable length message */
  // while(!FlagCableLengthValid)
  // {
    // ComM_MainFunction(); 
    // /* check incmomming message from host */
    // if(COMM_OK == ComM_ReadMsgFromQueue(&RxMsg))
    // {
      // /* The message indicates cable length to check */
      // if(RxMsg.MsgID == SS_MODE_SET_NBR_WIRES)
      // {
        // CableVerify.NbrOfWireToCheck = RxMsg.Data[0];
        // APP_MAIN_SavingData();
        // FlagCableLengthValid = 1;
      // }
      // else
      // {
        // /* do nothing */
      // }
    // }
    // else
    // {
      // /* do nothing */
    // }
  // }
  while(1)
  {
    ComM_MainFunction();  
    Port_AutoDetecting();
    /* check incmomming message from host */
    if(COMM_OK == ComM_ReadMsgFromQueue(&RxMsg))
    {
      Port_iProcessHostCommand(&RxMsg);
    }
    else
    {
      /* do nothing */
    }
  }
}

/* process auto detect cable  */
static void Port_AutoDetecting
(
  void
)
{
  INPUT_InputType i = IN_CH_1;
  /* check mode is auto */
  if(CableVerify.ActionMode == MODE_AUTO)
  {
    if(!CableDetected)
    {
      for(; i <= IN_CH_64 && !CableDetected; i++)
      {
        if(INPUT_ReadInput(i) == STD_LOW)
        {
          CableDetected = 1;
          BackTime = 200;
          /* cable detected */
          TxMsg.Port  = COMMUNICATION_PORT;
          TxMsg.DstID = HOST_NODE_ID;
          TxMsg.SrcID = PORT_NODE_ID;
          TxMsg.MsgID = SS_MODE_CABLE_DETECTED;
          TxMsg.Dlc   = 1;
          TxMsg.Data[0] = i;
          ComM_AddMessageToQueue(&TxMsg);  
        }
        else
        {
          /* do nothing */
        }
      }
    }
    else if(BackTime)
    {
      BackTime--;
      Timer_DelayMs(1);
      for(; i <= IN_CH_64 && BackTime != 200; i++)
      {
        if(INPUT_ReadInput(i) == STD_LOW)
        {
          CableDetected = 1;
          BackTime = 200;
          
        }
        else
        {
          /* do nothing */
        }
      }

    }
    else
    {
      CableDetected = 0;
    }
  }
  else
  {
    /* do nothing */
  }
}

/* process command from host  */
static void Port_iProcessHostCommand
(
  ComM_MessageType* msg
)
{
  uint8_t   LocalCounter = 0;
  /* check valid ID and port */
  if(msg->DstID == PORT_NODE_ID)
  {
    /* check command and execute functional according */
    for( ; LocalCounter < 5 ; LocalCounter++)
    {
      if(HostCommand[LocalCounter].Cmd == msg->MsgID)
      {
        HostCommand[LocalCounter].func(msg);
      }
      else
      {
        /* do nothing */
      }
    }
  }
  else
  {
    /* do nothing */
  }
}
/* process command switching mode  */
static void Port_iCmdSwitchingMode
(
  ComM_MessageType* msg
)
{
  CableVerify.ActionMode = (APP_MAIN_ActionModeType)msg->Data[0];
  APP_MAIN_SavingData();
}
/* process command from host  */
static void Port_iCmdStartCheck
(
  ComM_MessageType* msg
)
{
  CableVerify.NbrOfWireToCheck = msg->Data[0];
  CheckingStatus = FLG_START_CHECK;
  APP_MAIN_SavingData();
}
/* process command from host  */
static void Port_iCmdChecking
(
  ComM_MessageType* msg
)
{
	uint16_t i;
	COMST32_LogicLevel Input = STD_HIGH;
  Input  = INPUT_ReadInput((INPUT_InputType)msg->Data[0]);
  /* delay for cable is invalid */
  if( Input == STD_LOW )
  {
    /* wire PASSED */
    TxMsg.Port  = COMMUNICATION_PORT;
    TxMsg.DstID = HOST_NODE_ID;
    TxMsg.SrcID = PORT_NODE_ID;
    TxMsg.MsgID = SS_MODE_CABLE_PASSED;
    TxMsg.Dlc   = 1;
    TxMsg.Data[0] = msg->Data[0];
    ComM_AddMessageToQueue(&TxMsg);
  }
  else
  {
    /* wire FAILED */
    TxMsg.Port  = COMMUNICATION_PORT;
    TxMsg.DstID = HOST_NODE_ID;
    TxMsg.SrcID = PORT_NODE_ID;
    TxMsg.MsgID = SS_MODE_CABLE_FAILED;
    TxMsg.Dlc   = 1;
    TxMsg.Data[0] = msg->Data[0];
    ComM_AddMessageToQueue(&TxMsg);  
  }
}

/* thread check auto or manual mode */
static void Port_iStartDetect
(
  ComM_MessageType* msg
)
{
  INPUT_InputType   i = IN_CH_1;
  uint8_t           NbrWiresDetected = 0;
  uint16_t          TimeDetect = 0;
  /* check cable is detected */
  if(CableDetected)
  {
    do
    {
      ComM_MainFunction();
      if(!TimeDetect)
      {
        NbrWiresDetected = 0;
        for(i = IN_CH_1 ; i < (INPUT_InputType)msg->Data[0] && i <= IN_CH_64; i++)
        {
          if(INPUT_ReadInput(i) == STD_LOW)
          {
            NbrWiresDetected++;
          }
          else
          {
            /* do nothing */
          }
        }
        /* update number of wires are detected */
        TxMsg.Port  = COMMUNICATION_PORT;
        TxMsg.DstID = HOST_NODE_ID;
        TxMsg.SrcID = PORT_NODE_ID;
        TxMsg.MsgID = SS_MODE_START_DETECT;
        TxMsg.Dlc   = 1;
        TxMsg.Data[0] = NbrWiresDetected;
        ComM_AddMessageToQueue(&TxMsg);  
        TimeDetect = 500;
        /* transmit data */
        ComM_MainFunction();
        ComM_MainFunction();
        ComM_MainFunction();
      }
      else
      {
        TimeDetect--;
        Timer_DelayMs(1);
      }
    }while(NbrWiresDetected < (INPUT_InputType)msg->Data[0]);
  }
  else
  {
    /* do nothing */
  }
}

/* thread set nbr of wires to check */
static void Port_iSetCableLenght
(
  ComM_MessageType* msg
)
{
  CableVerify.NbrOfWireToCheck = msg->Data[0];
  APP_MAIN_SavingData();
}

/*******************************************************************************
** Function name: APP_MAIN_SavingData( void  )
** Description  : The function store configuration data to flash memory
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_SavingData
(
  void
)
{

  uint8_t *pData = (uint8_t*)&CableVerify;
  /* unlock  */
  Fls_Unlock(NULL_VAL,NULL_VAL,(Fls_FunctionCodeType)NULL_VAL);
  Fls_EraseSector(DATA_ADDRESS);
  Fls_ProgramPage(DATA_ADDRESS,sizeof(CableVerify),pData);
  Fls_Lock((Fls_FunctionCodeType)NULL_VAL);
}
/*******************************************************************************
** Function name: APP_MAIN_StartupValueSetting( void  )
** Description  : The function starts up all parameters
** Parameter    : none
** Return value : none
** Remarks      : global variables used, side effects
*******************************************************************************/
static void APP_MAIN_StartupValueSetting
(
  void
)
{
  uint8_t *BufferPtr = (uint8_t*)&CableVerify;
  uint16_t ReadSize = sizeof(CableVerify);
  uint32_t Address = DATA_ADDRESS;
  while(ReadSize)
  {
    *(BufferPtr++) = *(uint8_t*)Address;
    /* next address */
    Address++;
    /* decrement counter */
    ReadSize--;
  }
  /* check default setting */
  if(CableVerify.FirstSetup != 0xFAFA)
  {
    /* set default value */
    CableVerify.ActionMode = MODE_AUTO;
    CableVerify.FirstSetup = 0xFAFA;
    CableVerify.NbrOfWireToCheck =0;
    APP_MAIN_SavingData();
  
  }
  else
  {
    /* do nothing */
  }
}

